﻿using MTool.Domain;
using MTool.Domain.DO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace MTool.ViewModels
{
    class MainViewModel : ViewModelBase
    {
        #region Properties
        private Window window;
        private string _appTitle;
        public string AppTitle { get => _appTitle; set => SetProperty(ref _appTitle, value); }
        private ObservableCollection<ButtonViewModel> _buttons;
        public ObservableCollection<ButtonViewModel> Buttons { get => _buttons; set => SetProperty(ref _buttons, value); }

        private Dictionary<string, Func<string, string>> dicButtons;
        private string _inputText, _outputText;
        public string InputText { get => _inputText; set => SetProperty(ref _inputText, value); }
        public string OutputText { get => _outputText; set => SetProperty(ref _outputText, value); }

        #endregion
        #region ctor
        public MainViewModel(Window window)
        {
            this.window = window;

            init();
        }


        #endregion

        #region Commands
        private RelayCommand workCommand;
        public RelayCommand WorkCommand => workCommand ?? (workCommand = new RelayCommand(workClicked));


        #endregion

        #region Methods
        private void init()
        {
            AppTitle = $"{Constants.APP_NAME} v{Constants.VERSION}";
            initButtons();
        }
        private void initButtons()
        {
            Buttons = new ObservableCollection<ButtonViewModel>();
            dicButtons = new Dictionary<string, Func<string, string>>();

            string b64 = AppHelper.Inst.GetButtons();
            if (string.IsNullOrEmpty(b64))
            {
                Buttons = getDefaultButtons();
            }
        }



        #region 功能函数
        private string replaceSpace(string input)
        {
            input = input.Trim();
            return input.Replace(" ", "");
        }
        private string insertSpace(string input)
        {
            input = input.Trim();
            StringBuilder result = new StringBuilder();

            for (int i = 0; i < input.Length; i++)
            {
                result.Append(input[i]);
                if ((i + 1) % 2 == 0 && i < input.Length - 1)
                {
                    result.Append(' ');
                }
            }

            return result.ToString();
        }
        private string base64Encode(string input)
        {
            input = input.Trim();
            return Base64Util.Encode(input);
        }
        private string base64Decode(string input)
        {
            input = input.Trim();
            return Base64Util.Decode(input);
        }
        private string swap(string input)
        {
            InputText = OutputText;
            return input;
        }
        private string formatJsonString(string input)
        {
            string rt = "";
            input = input.Trim();

            try
            {
                var parsedObject = JObject.Parse(input);
                return parsedObject.ToString(Formatting.Indented);
            }
            catch (JsonReaderException)
            {
                // 处理解析错误
                rt += "Invalid JSON string\n";
            }
            try
            {
                rt += JsonParser.FormatJson(input);
            }catch(Exception e)
            {
                rt += e.Message;
            }

            return rt;
        }
        private string hex2Ascii(string input)
        {
            input = replaceSpace(input);

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < input.Length; i += 2)
            {
                string hexByte = input.Substring(i, 2);
                int decimalValue = Convert.ToInt32(hexByte, 16);
                char asciiChar = Convert.ToChar(decimalValue);
                sb.Append(asciiChar);
            }

            return sb.ToString();
        }
        private string asciiToHex(string input)
        {
            input = replaceSpace(input);

            StringBuilder sb = new StringBuilder();

            foreach (char c in input)
            {
                int asciiValue = (int)c;
                string hexValue = asciiValue.ToString("X2");
                sb.Append(hexValue);
            }

            return sb.ToString();
        }
        private string stringEquals(string input)
        {
            input = replaceSpace(input);
            var otext = OutputText.Trim();
            for (int i = 0; i < input.Length && i < otext.Length; i++)
            {
                if(input[i] != otext[i])
                {
                    MessageBox.Show($"不相等:{i + 1} {input[i]} {otext[i]}");
                    return null;
                }
            }

            if(otext.Length > input.Length)
            {
                MessageBox.Show("下面比上面长");
            }else if(input.Length > otext.Length)
            {
                MessageBox.Show("上面比上面长");
            }
            else
            {
                MessageBox.Show("相等");
            }

            return null;
        }
        #endregion
        private ObservableCollection<ButtonViewModel> getDefaultButtons()
        {
            var buttons = new ObservableCollection<ButtonViewModel>();

            ButtonViewModel vm;

            vm = createButtonViewModel("交换", swap);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("删除空格", replaceSpace);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("插入空格", insertSpace);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("Base64编码", base64Encode);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("Base64解码", base64Decode);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("JSON格式化", formatJsonString);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("十六进制转ASCII码", hex2Ascii);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("ASCII码转十六进制", asciiToHex);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            vm = createButtonViewModel("相等", stringEquals);
            dicButtons.Add(vm.Text, vm.Callback);
            buttons.Add(vm);

            return buttons;
        }

        private ButtonViewModel createButtonViewModel(string text, Func<string, string> callback)
        {
            ButtonViewModel vm = new ButtonViewModel();
            vm.ButtonCommand = WorkCommand;
            vm.Text = text;
            vm.Callback = callback;

            return vm;
        }
        private void workClicked(object obj)
        {
            ButtonViewModel bvm = obj as ButtonViewModel;
            if (null == bvm)
            {
                throw new ArgumentException("error viewModel");
            }

            Log.Debug($"clicked {bvm.Text}");

            var text = bvm.Callback?.Invoke(InputText);
            if (!string.IsNullOrEmpty(text))
            {
                OutputText = text;
            }

            bvm.SortField++;
        }

        public void Window_Closed(object sender, EventArgs e)
        {
            saveButtons();
        }
        public void Window_Loaded(object sender, RoutedEventArgs e)
        {
            loadButtons();
        }
        private void saveButtons()
        {
            List<ButtonDO> list = new List<ButtonDO>();
            foreach (var btn in Buttons)
            {
                list.Add(new ButtonDO { Text = btn.Text, Count = btn.SortField });
            }

            string json = JsonConvert.SerializeObject(list);
            Log.Debug($"save:{json}");
            string b64 = base64Encode(json);
            AppHelper.Inst.SetButtons(b64);
        }
        private void loadButtons()
        {
            string b64 = AppHelper.Inst.GetButtons();
            if (!string.IsNullOrEmpty(b64))
            {
                string json = base64Decode(b64);
                Log.Debug($"load:{json}");
                var btns = JsonConvert.DeserializeObject<List<ButtonDO>>(json);
                Log.Debug("loaded");

                Dictionary<string, ButtonDO> dic = new Dictionary<string, ButtonDO>();
                foreach (var btn in btns)
                {
                    dic.Add(btn.Text, btn);
                }
                // 按照 Count 属性进行升序排序
                //List<ButtonDO> sortedList = btns.OrderBy(button => button.Count).ToList();
                loadSortedButtons(dic);
            }
        }
        private void loadSortedButtons(Dictionary<string, ButtonDO> dic)
        {
            ObservableCollection<ButtonViewModel> buttons = new ObservableCollection<ButtonViewModel>();

            ButtonViewModel vm;

            var btns = getDefaultButtons();

            // set count
            foreach (var btn in btns)
            {
                if (dic.ContainsKey(btn.Text))
                {
                    btn.SortField = dic[btn.Text].Count;
                }
            }

            // sort
            var sortedButtons = btns.OrderByDescending(button => button.SortField).ToList();

            // add fixed buttons
            var first = AppHelper.Inst.GetFirst();
            var second = AppHelper.Inst.GetSecond();
            var third = AppHelper.Inst.GetThird();

            addFixed(first, sortedButtons);
            addFixed(second, sortedButtons);
            addFixed(third, sortedButtons);


            for (int i = 0; i < sortedButtons.Count; i++)
            {
                if(sortedButtons[i].Text != first 
                    && sortedButtons[i].Text != second
                    && sortedButtons[i].Text != third)
                {
                    Buttons.Add(sortedButtons[i]);
                }
            }
        }
        private void addFixed(string text, List<ButtonViewModel> sortedButtons)
        {
            if (!string.IsNullOrEmpty(text))
            {
                var btn = (from b in sortedButtons where b.Text == text select b).FirstOrDefault();
                if (null != btn)
                {
                    Buttons.Add(btn);
                }
            }
        }

        #endregion
    }
}
